package com.sexymobileframework.uicomponent;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;


public class UIComponentDescriptor 
{
	public static String m_sConfigDir;
	public static String m_sConfigFile;
	
	public String m_sAppID;
	
	public HashMap m_UIComponentsMap;
	
	public UIComponentDescriptor(String configDir, String configFile)
	{
		m_sConfigDir = configDir;
		m_sConfigFile = configFile;
		
		m_UIComponentsMap = new HashMap();
		
		//go through all the nodes starting from the current root node
		Element rootElement = getRootElement(m_sConfigDir, m_sConfigFile);
		
		if(rootElement != null)
		{
			getApplicationInfo(rootElement);
			getAllNodes(rootElement);
		}
		
		Iterator it = m_UIComponentsMap.entrySet().iterator();
		while(it.hasNext())
		{
			Entry entry = (Entry) it.next();
			UIComponent component = (UIComponent) entry.getValue();
			if(component.getParent() == null)
			{
				System.out.println(entry.getKey() + " parent: null");
			}
			else
			{
				System.out.println(entry.getKey() + " parent: " + component.getParent().getID());
			}
			
		}
		
		mergeIntoTemplate();
		
	}
	
	private void mergeIntoTemplate()
	{
		try
		{
			Velocity.init();
			VelocityContext context = new VelocityContext();
			context.put("descriptor", this);
			Template template = Velocity.getTemplate("./res/ui/UIConstants.vm");
			BufferedWriter writer = new BufferedWriter(new FileWriter("./src/UIConstants.java"));
			template.merge(context, writer);
			writer.close();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	private Element getRootElement(String configDir, String configFile) 
	{
		try
		{
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder parser = factory.newDocumentBuilder();
			Document doc = parser.parse(configDir + "//" + configFile);
			
			return doc.getDocumentElement();
		}
		catch (SAXException e) 
	    {
	    	System.out.println(configFile + " is not well-formed.");
	    	e.printStackTrace();
	    }
	    catch (IOException e) 
	    { 
	    	System.out.println("Exception opening: "  + configFile); 
	      	e.printStackTrace();
	    }
	    catch (FactoryConfigurationError e) 
	    { 
	      System.out.println("Could not locate a JAXP factory class");
	      e.printStackTrace();
	    }
	    catch (ParserConfigurationException e) 
	    { 
	      System.out.println("Could not locate a JAXP parser");
	      e.printStackTrace();
	    }
	    catch(Exception e)
	    {
	    	System.out.println("Error parsing UI configuration:");
	    	e.printStackTrace();
	    }
	    
		return null;
	}

	private void getAllNodes(Node currNode)
	{
		if(currNode.getNodeType() != Node.TEXT_NODE)
		{
			UIComponent newUIComponent = null;
			
			if(!currNode.getNodeName().equalsIgnoreCase("application"))
			{
				newUIComponent = getUIComponent(currNode);
				
				if(!m_UIComponentsMap.containsKey(newUIComponent.getID()))
				{
					if(!currNode.getParentNode().getNodeName().equalsIgnoreCase("application") && 
					   currNode.getParentNode().getNodeType() != Node.DOCUMENT_NODE)
					{
						UIComponent parentUIComponent = getUIComponent(currNode.getParentNode()); 
						
						if(m_UIComponentsMap.containsKey(parentUIComponent.getID()))
						{
							newUIComponent.setParent(parentUIComponent);
						}
					}
					
					m_UIComponentsMap.put(newUIComponent.getID(), newUIComponent);
				}
				
				
				
				
				if(currNode.getAttributes().getNamedItem("ref") != null)
				{
					String href = currNode.getAttributes().getNamedItem("ref").getNodeValue();
					String dir = m_sConfigDir + "//" + href.substring(0, href.lastIndexOf("/"));
					String file = href.substring(href.lastIndexOf("/") + 1);
					
					Element rootElement = getRootElement(dir, file);
					
					if(rootElement != null)
					{
						getAllNodes(rootElement);
					}
					
				}
			}
			
			//check if current node has sub nodes
			if(currNode.hasChildNodes())
			{
				for(int i = 0; i < currNode.getChildNodes().getLength(); i ++)
				{
					Node childNode = currNode.getChildNodes().item(i);
					getAllNodes(childNode);
				}
			}	
				
		}
			
	}
	
	private void getApplicationInfo(Node currNode)
	{
		if(currNode.getNodeName().equalsIgnoreCase("application"))
		{
			m_sAppID = currNode.getAttributes().getNamedItem("id").getNodeValue();

			System.out.println("*** application id: " + m_sAppID + " ***");
		}
	}
	
	private UIComponent getUIComponent(Node currNode)
	{
		return UIComponentFactory.createUIComponent(currNode);
	}
	
	public String getAppID()
	{
		return m_sAppID;
	}
	
	public Collection getUIComponents()
	{
		Collection<UIComponent> UIComponents = m_UIComponentsMap.values();
//		UIComponent[] sorted = new UIComponent[UIComponents.size()];
//		
//		int i = 0;
//		
//		for(UIComponent component : UIComponents)
//		{
//			sorted[i] = component;
//			i++;
//		}
//		
//		return Arrays.asList(sorted);
		return UIComponents;
	}
}
